const CFG = require('../config');
const FUN = require('../comm/func');
const rCache = require('../model/redis_cache');
const timLib = require('../comm/time-lib');
const dataCalc = require('../comm/data-calc');
const dbPcyData = require('../model/model_data');
const dbHelp = require('../comm/db-helper');
const mbLib = require('../comm/modbus-lib');
const PMR = require('../utils/policyManger');

module.exports = class DiffAlarm
{
  //将数据库选项缓存到redis
  //policy 来自数据库的记录
  //opts 数据库json字段的解析对象
  //CacheCallback 存储执行函数
  static InitCache(policy,opts,CacheCallback)
  {
    let obj=PMR.baseParam(policy);//即将缓存到redis的参数

    //json options参数存储
    obj.record_limit = policy.record_limit;//数据库条数上限
    obj.diff = opts.diff;//偏差
    obj.excep = opts.excep;//剔除值
    obj.group = opts.group;//组别
    obj.gname = opts.gname;//组名
    obj.only_once = opts.only_once;//是否只报警一次 true,false
    obj.msg = opts.msg;
    obj.enable = opts.enable;//屏蔽开关 true,false

    //数据库处理
    dbHelp.createTab(obj.table,policy.uid);

    //缓存主站参数
    obj.hwid = policy.master;
    obj.role = 'master';
    obj.brother = policy.brother;
    CacheCallback(policy.id,policy.master,obj);//记录到缓存
    //rCache.delNode(PMR.rdNode(obj));//删除之前的历史记录
    rCache.delNode(PMR.rdNode(obj));//删除旧的only_once信息

    //缓存从站参数
    if(Number(policy.brother) && policy.brother!=-1)
    {
      obj.hwid = policy.brother;
      obj.role = 'slave';
      obj.brother = policy.master;
      CacheCallback(policy.id,obj.hwid,obj);//记录到缓存
      //rCache.delNode(PMR.rdNode(obj));//删除之前的历史记录
    }
  } // end InitCache

  //modbus数据总分析
  // topic = {project,devType,func,devId}
  // dConf即InitCache中的obj
  // dataBuf即mq消息内容，buf对象
  static async DataIn(topic, dConf, dataBuf)
  {
    mbLib.mbPacketParse(topic.func, dConf, dataBuf, (last,sConf)=>{
      rCache.getKey(PMR.rdNode(dConf),'db_stamp').then((db_stamp)=>{
        let stamp=timLib.NowStamp();
        if(db_stamp!=null && stamp-db_stamp<CFG.DATA_SAVE_GAP)//存储到数据库的频率不能过快
        {pcyLog('[%d] real fast(%dmS)',dConf.hwid,stamp-db_stamp);return;}
        this.dataHandler(last,sConf,dataBuf,stamp);
      })//end getKey
    })
  }//end function ModbusTx


  //普通的数据处理,每隔一段时间就求平均值入数据库
  static dataHandler(last,dConf,data,stamp)
  {
    dConf.data_width='2:n';

    //记数值
    let save=[];
    let regValArray={};
    let data_fmt=dConf.data_width.split(':');//分割数据宽度和数据格式
    for(let i=0;i<last.regNum;i+=(data_fmt[0]/2))
    {
      let reg=Number(last.regStart)+i;
      let regVal=(Number(data[3+i*2])<<8)+Number(data[4+i*2]);

      if(data_fmt[0]==4)//不同字节长度得的处理
        regVal=(regVal<<16)+(Number(data[5+i*2])<<8)+Number(data[6+i*2]);

      if(data_fmt[1]=='f') regVal=FUN.ieee745_toFloat(regVal).toFixed(4);
      save.push({reg:reg,value:regVal,name:'#'+last.addr+':'+reg});//加入到数组
      regValArray['#'+last.addr+':'+reg]=regVal;//构建对象，暂存数据
    }

    //读取分组信息
    let group=dConf.group.split(',');
    let gArray=[];
    let gArrayIdx=[];

    for(let i in group)//轮询每个组，存下有数值的
    {
      let gone=group[i].split('-');//#1:3-6
      if(gone.length<2) continue;
      let start=gone[0].split(':');
      if(start.length<2) continue;

      let hasVal=true;
      let num=Number(gone[1]);
      let one=[];
      for(let n=0;n<num;n++)
      {
        one[n]=start[0]+':'+(Number(start[1])+n);
        if(typeof(regValArray[one[n]])=='undefined') hasVal=false;
      }

      if(hasVal){
        gArray.push(one);
        gArrayIdx.push(i);
      }
    }

    //处理数值
    for(let i in gArray)
    {
      let vaildNum=0;
      let max=-9999999999;
      let min=9999999999;

      for(let reg of gArray[i])
      {
        let excep=dConf.excep.split(',');
        let regVal=Number(regValArray[reg]);

        if(!excep.includes(regVal.toString()))
        {
          vaildNum++;
          if(regVal>max) max=regVal;
          if(regVal<min) min=regVal;
        }
      }

      if(vaildNum>1 && max-min>Number(dConf.diff))
      {
        //pcyLog('alarm',max,min,vaildNum);
        this.alarmHandler(gArrayIdx[i],max-min,dConf);
      }
    }

  }//end funciton


  //报警处理
  static alarmHandler(idx,realDiff,dConf)
  {
    if(dConf.enable!='true') return;

    //找到缓存的寄存器值
    rCache.getKey(PMR.rdNode(dConf),idx).then((flag)=>{
      if(dConf.only_once=='true') rCache.setKey(PMR.rdNode(dConf),idx,1);//单次报警模式
      if(flag=='1'){pcyLog('[%d][%d] already alarm',dConf.policy_id,dConf.hwid);return;}//单次报警模式

      let gName=dConf.gname.split(',');
      let stamp=timLib.NowStamp();
      let msg=dConf.msg.split('|')[idx];

      //处理消息变量替换
      msg=msg?msg:dConf.msg;
      msg=msg.replace(/#sn/g,Number(idx)+1);
      msg=msg.replace(/#name/g,gName[idx]);
      msg=msg.replace(/#diff/g,realDiff);

      //替换算式的运算结果
      let calc=msg.match(/\${.+?}/g);//找到类似${405*10}这样的算式
      if(calc)
      for(let c of calc){
        let regex=/\${(.+?)}/g;
        let cVal=eval(regex.exec(c)[1]);//找出${}里的内容，并执行
        if(cVal!=null) msg=msg.replace(c,cVal);
      }

      //发出报警消息
      //pcyLog('msg',dConf.policy_id,msg);
      pcyLog('[%d][%d] diff-alram',dConf.policy_id,dConf.hwid,gName[idx],timLib.NowStr());
      dbPcyData.addAlaramLog(dConf.uid, dConf.hwid, dConf.policy_id, idx, msg, stamp).then((id)=>{
        PMR.alarmReport(id,dConf);
      })

      //删除数据库中冗余的前期数据
      dataCalc.dbRecordTidy(dConf.uid,dConf.table,dConf.policy_id,dConf.record_limit);
    })//end getKey regVal
  }//end function



} //end class Modbus